<template>
  <view>
    <view id="tv-page_0x00" :prop="customKeyMap" :change:prop="tv.propChanged" @click="tv.controlClick"></view>
    <slot></slot>
  </view>
</template>

<script>
/**
 * tv-page tv页面
 * @description 类似于page，声明一个TV端页面，包含按键监听、参数配置等核心功能
 * @property { preventDefault } 阻止默认事件
 * @property { debugger } 显示调试信息
 * @property { customKeyMap } 自定义按键映射
 */
export default {
  name: 'TvPage',
  componentName: 'TvPage',
  provide() {
    return {
      tvPage: this
    };
  },
  props: {
    // 阻止默认事件
    preventDefault: {
      type: Boolean,
      default: false
    },
    // 显示调试信息
    debugger: {
      type: Boolean,
      default: false
    },
    // 自定义按键映射
    customKeyMap: {
      type: Object,
      default: () => ({})
    }
  },
  data: () => ({
    keyType: '', // 按键类型
    focused: null, // 焦点对象
    children: [] // 子组件
  }),
  methods: {
    /**
    * 接收按键事件
    * @param {String} keyType 按键类型
    * @param {Number} keyCode 按键编码
    */
    serviceControlClick({ keyType, keyCode }) {
      this.keyType = keyType;
      this.dispatchKeyEvent(keyType, keyCode);
      // 显示按键信息
      this.debugger && this.showControlInfo(keyType, keyCode);
    },
    /**
    * 显示按键信息
    * @param {String} keyType 按键类型
    * @param {Number} keyCode 按键编码
    */
    showControlInfo(keyType, keyCode) {
      uni.showToast({
        title: `按键类型：${keyType}，按键编码：${keyCode}`,
        icon: 'none',
        duration: 2000
      });
    },
    /**
    * 派遣按键事件
    * @param {String} keyType 按键类型
    * @param {Number} keyCode 按键编码
    */
    dispatchKeyEvent(keyType, keyCode) {
      // 有焦点对象，向焦点对象派遣按键事件
      if (this.focused) {
        return this.focused.dispatchKeyEvent(keyType, keyCode);
      }
      // 没有焦点对象，寻找焦点area
      this.findFocusArea();
    },
    /**
    * 寻找焦点area
    */
    findFocusArea() {
      if (this.children.length) {
        const area = this.children.find(v => v.$options.componentName === 'TvArea');
        area && area.setFocusArea();
      }
    }
  }
};
</script>

<script module="tv" lang="renderjs">
import { keyMap, plusKeyTypeMap } from '../../config/index.js'
export default {
  data: () => ({
    keyMap
  }),
  methods: {
    /**
    * 监听按键
    * @param {Object} e 事件对象
    */
    watchControl(e) {
      this.keyCode = e.keyCode || e.which;
      this.keyType = Object.keys(this.keyMap).find(v => this.keyMap[v].includes(this.keyCode));
      this.keyType && window.document.querySelector('#tv-page_0x00').click();
    },
    /**
    * 传递按键事件到 service 层
    * @param {Object} event 事件对象
    * @param {Object} ownerInstance 页面实例
    */
    controlClick(event, ownerInstance) {
      // 调用 service 层的方法
      ownerInstance.callMethod('serviceControlClick', { keyType: this.keyType, keyCode: this.keyCode })
    },
    /**
    * 接收视图层参数
    * @param {Object} e 事件对象
    */
    propChanged(e) {
      Object.assign(this.keyMap, e);
    },
    // 添加按键监听
    addEventListener() {
      window.addEventListener('keydown', this.watchControl);
      // #ifdef APP-PLUS
      plusKeyTypeMap.forEach(v => plus.key.addEventListener(v, this.watchControl));
      // #endif
    },
    // 移除按键监听
    removeEventListener() {
      window.removeEventListener('keydown', this.watchControl);
      // #ifdef APP-PLUS
      plusKeyTypeMap.forEach(v => plus.key.removeEventListener(v, this.watchControl));
      // #endif
    }
  },
  mounted() {
    this.addEventListener();
  },
  destroyed() {
    this.removeEventListener();
  },
  activated() {
    this.addEventListener();
  },
  deactivated() {
    this.removeEventListener();
  }
}
</script>
